#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/time.h>

#include "./include/os_struct.h"

#define MAXFRAME	16
#define INFOSIZE	2400		

struct FramePortInfos {
	uint8_t dyb_portinfo[INFOSIZE*MAXFRAME];

	uint8_t zkb_rep0d[MAXFRAME][10]; /* zkb这3个字母是主控板的首字母的缩写，jkb代表接口板，dyb代表单元板的意思*/	
	uint8_t zkb_repA6[MAXFRAME][10]; /* rep这3个字母是英文reply的意思，即代表主控回复接口板的命令数组 */
	uint8_t zkb_rep20[MAXFRAME][10]; /* 0d/20/A6 分别代表了要发送给接口板的数据命令 */
	uint8_t zkb_rxBuf[INFOSIZE];

   uint32_t zkb_stats[MAXFRAME];     /* zkb_stats用来表示主控板中记录着哪些框是要采集的，其中设置1表示要采集，0xdead表示不存在这个框 */	
   uint32_t jkb_stats[MAXFRAME];     /* jkb_stats这个数组用来存放那些要采集的框，在采集进行中的状态变化*/

	struct  timeval timeBegin;
	struct  timeval timeOut;

}PortsInfo;	

extern int uart0fd;
extern OS_BOARD s3c44b0x;

/*
 * 该函数只能在资源采集的时候使用
 *
 */
static unsigned char calccrc8(uint8_t* ptr,uint32_t len)
{
	unsigned char  i = 0,crc = 0;

	while(len--){
		i = 0x80;
		while(i != 0){
			if(((crc & 0x80) != 0) && (((*ptr) & i) != 0)){
				crc <<= 1;
			}else if(((crc & 0x80)!= 0) && (((*ptr) & i)==0)){
  			    crc <<= 1;
			 	crc ^= 0x31;
  			}else if(((crc & 0x80) == 0)&& (((*ptr) & i) !=0)){
       			crc <<= 1;
	 			crc ^= 0x31;
  			}else if(((crc & 0x80) == 0) &&(((*ptr)&i)== 0)){
  			   crc <<= 1;
  			}
  			i >>= 1;
		}
		ptr++;
	}

	return(crc);
} 

/****************************************************************************
   Fuction     : 
   Description : 在主控板向接口板的每个框发起采集命令的时候，提前准备一些数据
   Call        : 不调用其他任何外部函数
   Called by   : 该函数仅被module_mainBoard_resource_handle()这个函数调用
   Input       : 网管发来的采集数据，这里主要区分是一次采集还是二次采集
              
   Output      : 不对外输出
   Return      : 无返回值
                 
   Others      : 无其他说明
 *****************************************************************************/
static void zkb_txBuf_data_tianchong(unsigned char *src)
{
	unsigned char idex = 0;
	unsigned char zkb_pol[7] = {0x7e, 0x00, 0x05, 0x20, 0x00, 0x00, 0x5a};		/*zkb_pol is short for zkb_poll_cmd */
	unsigned char zkb_col[8] = {0x7e, 0x00, 0x06, 0x0d, 0x01, 0x00, 0x00, 0x5a};/*zkb_col is short for zkb_collect_cmd */	
	unsigned char zkb_rep[9] = {0x7e, 0x00, 0x07, 0xa6, 0x0d, 0x00, 0x00, 0x00, 0x5a};

	/* clear array */
	for(idex = 0; idex < MAXFRAME; idex++){
		memset(&PortsInfo.zkb_rep0d[idex][0], 0, 10);
		memset(&PortsInfo.zkb_repA6[idex][0], 0, 10);
		memset(&PortsInfo.zkb_rep20[idex][0], 0, 10);
	}
	
	/* Judge first time collect or Second time collect*/
	if(0x23 == src[3] || 0x24 == src[3]){
		zkb_col[4] = 0x11;
	}else if(0x20 == src[3]){
		zkb_col[4] = 0x01;
	}

	/* tianchong cmd 0x0d to PortsInfo.zkb_rep0d */
	for(idex = 0; idex < MAXFRAME; idex++){
		zkb_col[5] = idex + 1;
		zkb_col[6] = calccrc8(zkb_col, 6);
		memcpy(&PortsInfo.zkb_rep0d[idex][0], zkb_col, zkb_col[1]<<8|zkb_col[2]+2);
	}

	/* tianchong 0xA6/0xF6 PortsInfo.zkb_repA6 / PortsInfo.zkb_repF6 */
	for(idex = 0; idex < MAXFRAME; idex++){
		zkb_rep[5] = zkb_col[4];
		zkb_rep[6] = idex + 1;
		zkb_rep[7] = calccrc8(zkb_rep, 7);
		memcpy(&PortsInfo.zkb_repA6[idex][0], zkb_rep, zkb_rep[1]<<8|zkb_rep[2]+2);	
	}

	/* tianchong 0x20 PortsInfo.zkb_rep20 */
	for(idex = 0; idex < MAXFRAME; idex++){
		zkb_pol[4] = idex + 1;
		zkb_pol[5] = calccrc8(zkb_pol, 5);
		memcpy(&PortsInfo.zkb_rep20[idex][0], zkb_pol, zkb_pol[1]<<8|zkb_pol[2]+2);	
	}

	/* set jkb default value 1*/
	memset(&PortsInfo.jkb_stats[0], 0, MAXFRAME);
	for(idex = 0; idex < MAXFRAME; idex++){
		if(s3c44b0x.frameactive[idex]){
			PortsInfo.jkb_stats[idex] = 1;
			PortsInfo.zkb_stats[idex] = 1;
		}else 
			PortsInfo.jkb_stats[idex] = 0xdead;
	}

	/* reround time count */
	PortsInfo.timeBegin.tv_sec = 0;
	PortsInfo.timeBegin.tv_usec = 0;
	PortsInfo.timeOut.tv_sec = 0;
	PortsInfo.timeOut.tv_usec = 0;

	/*clear dyb_portinfo*/
	memset(&PortsInfo.dyb_portinfo[0], 0, MAXFRAME*INFOSIZE);
	PortsInfo.dyb_portinfo[3] = src[3];
}	
/****************************************************************************
   Fuction     :
   Description : 根据主控板识别的下面挂载的框数量决定采集的超时时间
   Call        : 不调用任何其他函数
   Called by   : 仅在module_resource.c文件中内部调用
   Input       : 
              param[0]: devicesnum, 主控板在上电的时候，识别的外部的框数量
   Return      : 返回计算出来的采集上限时间
                 
   Others      : 无任何其他说明
 *****************************************************************************/
static uint32_t calc_collect_time_deadline(uint8_t devicesnum)
{
	return 1000000*(20/16)*devicesnum + 3000000;
}
/****************************************************************************
   Fuction     : 
   Description : 资源采集主体函数中的接收并处理接口板发来数据的模块
   Call        : 
   Called by   : 只被 module_mainBoard_resource_handle()函数调用
   Input       : 
              
   Return      : 
                 
   Others      : 
 *****************************************************************************/
static uint32_t zkb_txBuf_data_part(void)
{
	static uint8_t jkb_num = 1;
	uint8_t ret_jkb_num = jkb_num;

	if(0xdead == PortsInfo.jkb_stats[jkb_num - 1]) {
		return 0xdead;
	}else if(0x01 == PortsInfo.jkb_stats[jkb_num - 1]){
		write(uart0fd, &PortsInfo.zkb_rep0d[jkb_num - 1][0], PortsInfo.zkb_rep0d[jkb_num-1][1]<<8|PortsInfo.zkb_rep0d[jkb_num-1][2]+2);
		usleep(300000);
	}else if(0x02 == PortsInfo.jkb_stats[jkb_num - 1]){
		write(uart0fd, &PortsInfo.zkb_rep20[jkb_num - 1][0], PortsInfo.zkb_rep20[jkb_num-1][1]<<8|PortsInfo.zkb_rep20[jkb_num-1][2]+2);
		usleep(500000);
	}else if(0x03 == PortsInfo.jkb_stats[jkb_num - 1]){
		return 0;
	}
	
	jkb_num += 1;
	if(jkb_num > MAXFRAME)
		jkb_num = 1;

	return ret_jkb_num;
}

/****************************************************************************
   Fuction     : zkb_rxBuf_data_part(uint32_t jkb_num)
   Description : 资源采集过程中，主控板处理接口板发来的数据的处理模块 
   Call        : 该函数没有调用任何其他的函数
   Called by   : 该函数仅被process_main.c调用
   Input       : 
                 param[0]：当前正在巡检的接口板的编号
   Output      : 无对外输出
   Return      : 
                 0：表示收到的接口板发来的数据无效
				 1：表示收到的接口板发来的数据有效，并被正确的解析了。
   Others      : 无其他描述
 *****************************************************************************/
static uint8_t zkb_rxBuf_data_part(uint32_t jkb_num)
{
	int nBytes = 0x0, nlength = 0x0;
	uint32_t dyb_portinfo_storedidex= 0, eidType = 32;

	nBytes = read(uart0fd, &PortsInfo.zkb_rxBuf, INFOSIZE);
	if(nBytes <= 0){
		return 0;/* msg invalid*/
	}else{
		nlength = PortsInfo.zkb_rxBuf[1]<<8|PortsInfo.zkb_rxBuf[2];
		if(nlength > INFOSIZE){
			return 0;/* msg invalid */
		}else{
			if(PortsInfo.zkb_rxBuf[nlength] == calccrc8(&PortsInfo.zkb_rxBuf[0], nlength)){
				/*crc right ! msg valid */
				if(0xa6 == PortsInfo.zkb_rxBuf[3]){
					PortsInfo.jkb_stats[jkb_num - 1] = 0x2;	
				}else if(0x01 == PortsInfo.zkb_rxBuf[4] || 0x11 == PortsInfo.zkb_rxBuf[4]){
					dyb_portinfo_storedidex = (PortsInfo.zkb_rxBuf[5] - 1)*(((eidType*12+8)*6)+5) + 126;
					memcpy(&PortsInfo.dyb_portinfo[dyb_portinfo_storedidex], &PortsInfo.zkb_rxBuf[5], (((eidType*12)+8)*6+5));
					nlength = PortsInfo.zkb_repA6[jkb_num-1][1]<<8|PortsInfo.zkb_repA6[jkb_num-1][2];
					write(uart0fd, &PortsInfo.zkb_repA6[jkb_num-1][0], nlength+2);	
					usleep(250000);
					PortsInfo.jkb_stats[jkb_num - 1] = 0x3;	
				}
				return 1;
			}else{
				/* 收到接口发来的数据校验后发现crc不对,因此返回0*/
				return 0;
			}
		}
	}

}

/****************************************************************************
   Fuction     :
   Description : 检查是不是所有的框都采集完成了
   Call        : 
   Called by   : 
   Input       : 
              
   Output      : 
   Return      : 
                 
   Others      : 
 *****************************************************************************/
static uint32_t zkb_check_collectTask_Done(void)
{
	uint8_t idex = 0 , finishedFrames = 0;

	for(idex = 0; idex < MAXFRAME; idex++){
		if((0x1 == PortsInfo.zkb_stats[idex]) && (0x03 == PortsInfo.jkb_stats[idex])){
			finishedFrames += 1;
		}
	}

//	printf("%d frames not collect Done , finished %d frameNums, total = %d \n", 
//					s3c44b0x.totalactiveDevices - finishedFrames, finishedFrames, s3c44b0x.totalactiveDevices);

	if(finishedFrames == s3c44b0x.totalactiveDevices){
		printf("collect task Done \n");
		return 1;
	}

	return 0;
}
/****************************************************************************
   Fuction     :
   Description : 最后一步骤，组织数据并发送给网管
   Call        : 
   Called by   : 
   Input       : 
              
   Output      : 
   Return      : 
                 
   Others      : 
 *****************************************************************************/
static uint32_t zkb_upload_portinfo_to_webmaster(int fd)
{
	uint32_t feedbackBytes = 0;

	feedbackBytes   = s3c44b0x.frameNums*(((32*12+8))*6+5)+126;	

	PortsInfo.dyb_portinfo[0] = 0x7e;
	PortsInfo.dyb_portinfo[1] = feedbackBytes >> 8 & 0xff;
	PortsInfo.dyb_portinfo[2] = feedbackBytes & 0xff;
//	PortsInfo.dyb_portinfo[3] = 0x20; 
	memcpy(&PortsInfo.dyb_portinfo[4],s3c44b0x.manufacturer,4);
	memcpy(&PortsInfo.dyb_portinfo[8],s3c44b0x.uuid,16);
	memcpy(&PortsInfo.dyb_portinfo[42],s3c44b0x.deviceName,80);	
	PortsInfo.dyb_portinfo[41]  = s3c44b0x.sortStyle;
	PortsInfo.dyb_portinfo[122] = s3c44b0x.hd_version >> 8 & 0xff;
	PortsInfo.dyb_portinfo[123] = s3c44b0x.hd_version & 0xff;
	PortsInfo.dyb_portinfo[124] = s3c44b0x.sf_version >> 8 & 0xff;
	PortsInfo.dyb_portinfo[125] = s3c44b0x.sf_version & 0xff;
	PortsInfo.dyb_portinfo[feedbackBytes] = calccrc8(&PortsInfo.dyb_portinfo[0],feedbackBytes); 
	PortsInfo.dyb_portinfo[feedbackBytes+1] = 0x5a;	 
	
	if(send(fd,&PortsInfo.dyb_portinfo,feedbackBytes+2,0) == -1){
		close(fd);
	}else{
		close(fd);
	}

	return 0;
}

/****************************************************************************
   Fuction     :
   Description : 资源采集主体函数
   Call        : 调用了下面4个函数
   				 zkb_txBuf_data_tianchong()
				 zkb_txBuf_data_part()
				 zkb_rxBuf_data_part()
                 zkb_upload_portinfo_to_webmaster()

   Called by   : 被process_main.c文件调用该函数
   Input       : 
              
   Output      : 
   Return      : 
                 
   Others      : 
 *****************************************************************************/
int module_mainBoard_resource_handle(unsigned char *src,int client_fd)
{
	volatile uint32_t totaltimeuse = 0x0, timeDeadline = 0x0;
	volatile uint32_t c_frame = 0x0, retval = 0x0;

	zkb_txBuf_data_tianchong(src);

	timeDeadline = calc_collect_time_deadline(s3c44b0x.totalactiveDevices);

	gettimeofday(&PortsInfo.timeBegin, NULL);
	while(totaltimeuse < timeDeadline)
	{
		c_frame = zkb_txBuf_data_part();
		if((0xdead != c_frame) && (0x0 != c_frame)){
			zkb_rxBuf_data_part(c_frame);
			retval = zkb_check_collectTask_Done();
			if(retval){
				zkb_upload_portinfo_to_webmaster(client_fd);
			}
		}	
		
		gettimeofday(&PortsInfo.timeOut,NULL);
		totaltimeuse = (1000000*(PortsInfo.timeOut.tv_sec - PortsInfo.timeBegin.tv_sec)
			+ PortsInfo.timeOut.tv_usec - PortsInfo.timeBegin.tv_usec);	
	}

	/*it's so sorry enter here*/	
	zkb_upload_portinfo_to_webmaster(client_fd);

	return 0;
}


/****************************************************************************
   Fuction     :
   Description : 二次采集最后的覆盖模块
   Call        : 
   Called by   : 
   Input       : 
              
   Output      : 
   Return      : 
                 
   Others      : 
 *****************************************************************************/
int second_resource_collect_recover_task(unsigned char *src,int sockfd)
{
	return 0;
}
